# lvm-lib.pl
use Data::Dumper;
do '../web-lib.pl';
&init_config();
#%hwinfo = hwinfo("diskman");
%access = get_module_acl();
#Get PV info list;



sub get_raidcard_info
{
	my $rdtype;
	my @abc;
	open(RT, "/etc/raidtype");
	@abc=<RT>;
	close(RT);
	$rdtype = $abc[0];
	$rdtype =~ s/\r|\n//g;
	return $rdtype;
}

sub get_fstype
{
	my $dev=$_[0];
	my ($vg, $lv, $dname, $fstype);
	$dev =~ /^\/dev\/(vg\d)\/(volume\d+)/;
	$vg = $1;
	$lv = $2;
	$dname = "/dev/mapper/".$vg."-".$lv;
	if(-e "/dev/mapper/$lv"){
		$dname="/dev/mapper/$lv";
	}
	$rc = `file -s $dname 2>/dev/null`;
	if($rc =~ /ext3/){
		$fstype = "ext3";
	}
	elsif($rc =~ /XFS/){
		$fstype = "xfs";
	}
	else{
		$fstype = "nofs";
	}
	return $fstype;
}

sub get_pv_info
{
	my @pvinfo=();
	my @pvinfob;
	my @raidinfo;
	my $cardtype = get_raidcard_info();
	if($cardtype =~ /3ware/){
		@raidinfo = get_raid_info_3w();
	}
	elsif($cardtype =~ /lsi/){
		@raidinfo = get_raid_info_lsi();
	}
	elsif($cardtype =~ /hpt/){
		@raidinfo = get_raid_info_2220();
	}
	elsif($cardtype = /areca/){
		@raidinfo = get_raid_info_areca();
	}

	my ($pv, $vg, $size, $free, $unit);
	open(PV, "lvm pvs --noheadings --unit g 2>/dev/null |");
	my $i = 0;
	while($line = <PV>) {
		$line =~ s/\r|\n//g;
		$line =~ s/#.*$//g;	
		if ($line =~ /\s+(\S+)\s+(\S+)\s+\S+\s\S+\s+(\S+)G\s+(\S+)G/) {
			$pv = $1;
			$vg = $2;
			$size = $3;
			$free = $4;
			$i++;
                	$pvinfo[$i]->{'pv'} = $pv;
			$pvinfo[$i]->{'raid'} = get_raid_of_pv($pv, @raidinfo);
                	$pvinfo[$i]->{'vg'} = $vg;
                	$pvinfo[$i]->{'size'} = $size;
                	$pvinfo[$i]->{'free'} = $free;
		}
                elsif($line =~ /\s+(\S+)\s+(\S+)\s+\S+\s\S+\s+(\S+)G\s+0/){
                        $pv = $1;
                        $vg = $2;
                        $size = $3;
                        $free = 0;
                        $i++;
                        $pvinfo[$i]->{'pv'} = $pv;
                        $pvinfo[$i]->{'raid'} = get_raid_of_pv($pv, @raidinfo);
                        $pvinfo[$i]->{'vg'} = $vg;
                        $pvinfo[$i]->{'size'} = $size;
                        $pvinfo[$i]->{'free'} = $free;
                }		
		elsif ($line =~ /\s+(\S+)\s+\S+\s+(\S+)\s+(\S+)G\s+(\S+)G/) {
			$pv = $1;
			$vg = "";
			$size = $3;
			$free = $4;
			$i++;
			$pvinfo[$i]->{'pv'} = $pv;
			$pvinfo[$i]->{'raid'} = get_raid_of_pv($pv, @raidinfo);
			$pvinfo[$i]->{'vg'} = $vg;
			$pvinfo[$i]->{'size'} = $size;
			$pvinfo[$i]->{'free'} = $free;
		}
		else{
			next;
		}
	}
	close(PV);
	foreach $pvi (@pvinfo) {
		if($pvi->{'pv'}){
			push(@pvinfob, $pvi);
		}
	}
	return @pvinfob;
}

# Get Raid info of PV;
sub get_raid_of_pv
{
	my ($pv, @raid) = @_;
	my $r;
	foreach $r (@raid) {
		if ($r->{'name'} eq $pv) {
			return $r->{'volname'};
		}
	}
	my $re = "";
	return $re;
}

#get raid name : for 3ware raid adapter only!
sub get_3w_volname
{
    $cid = `/sbin/tw_cli/tw_cli show |grep c[0-9]`;
    $cid =~ /^(c\d+)\s+/;
    $cid = $1;
    $config{'amccpath'} = "/sbin/tw_cli/tw_cli";
    $temp = $config{'amccpath'}." /$cid/".$_[0]." show name 2>/dev/null |";
    open(AMCC, $temp);
    @amcc=<AMCC>;
    close(AMCC);
    foreach(@amcc){
       if($_ =~ /=\s(\S+)/){
           return $1;
       }
    }
}

#Get scsi dev of raid: for 3ware adapter only!
sub get_scsidev_3w
{
   $unitname = $_[0];
   @capt = (b, c, d, e, f, g, h, i, j, k, l, "m", n, o, p);
   if($unitname =~ /^u(\d)/){
       $ca = $capt[$1];
       $devname = '/dev/sd'.$ca;
   }
   return $devname;
}

#-----------------------------------------#
# The following subs are used for  rewrite
# unit scsi device config file:
# /etc/nas/sdinfo
#-----------------------------------------#
sub get_scsi_dev
{
   my @sd;
   open(SCSI, "fdisk -l /dev/sd* 2>/dev/null |");
   @scsidev = <SCSI>;
   close(SCSI);
   foreach(@scsidev)
   {
     if($_ =~ /^Disk\s(\/dev\/sd\S):\s+\S+\s+[GT]B/)
     {
       #print $1;
       push(@sd, $1);
     }
   }
   return @sd;
}



sub get_raid_info_lsi
{
	open(RI, "/sbin/MegaCli -ldpdinfo -a0|");
	@lsi = <RI>;
	close(RI);
	$num = @lsi;
	
	my @name=();
	$p = 0;
	for($j=0; $j<$num; $j++) {
		if($lsi[$j] =~ /^Virtual\s+Disk:\s+(\d+)\s+\(Target\s+Id:\s+(\d+)\)/){
			$m = $2;
			for($k=$j+1; $k<$num; $k++){
				if($lsi[$k] =~ /^Virtual\s+Disk:\s+(\d+)\s+\(Target\s+Id:\s+(\d+)\)/){
					last;
				}
				elsif($lsi[$k] =~ /Name:(diskarray\d+)/){
					$n = $1;	
				}
			}
			
			$name[$m] = $n;
			#$name[$p] = $n;
			$p++;
		}
		else{
			next;
		}
	}
	my @newname;
	foreach (@name) {
		if ($_ =~ /diskarray\d+/) {
			push(@newname, $_);
		}
	}
	my @scsidevs = get_scsi_dev();
	$snum = @scsidevs;	
	my ($rdinfo, @raidinfo_cache);
	$rdinfo = \@raidinfo_cache;
	for($i=0; $i<$snum; $i++){
		$rdinfo->[$i]->{'id'} = $i;		#rdinfo->[0]->{'id'} = 0
		$rdinfo->[$i]->{'name'} = $scsidevs[$i]; 	#rdinfo->[0]->{'name'} = /dev/sda
		$rdinfo->[$i]->{'volname'} = $newname[$i]; 	 #rdinfo->[0]->{'volname'} = 'diskarray1';
	}
	
	return @raidinfo_cache;
}
sub get_raid_info_areca
{
	my ($hrdinfo, @lsraid_info);
	$hrdinfo = \@raidinfo_cache;
	$cmd = '/sbin/cli32 vsf info 2>/dev/null |';
	open(VS, $cmd);
	while($line=<VS>){
        if($line =~ /^\s+(\d+)\s+(\S+)\s+(\d+)\s+(\S+)\s+(\S+)GB\s+(\S+)\s+(\S+)/){
		$id=$1;
                $hrdinfo->[$i]->{'id'} = $1;
		if($id == 1){
			$hrdinfo->[$i]->{'name'} = '/dev/sda';
		}
		elsif($id == 2){
			$hrdinfo->[$i]->{'name'} = '/dev/sdb';
		}
		elsif($id == 3){
			$hrdinfo->[$i]->{'name'} = '/dev/sdc';
		}
                $hrdinfo->[$i]->{'volname'} = $2;
                $hrdinfo->[$i]->{'raidset'} = $3;
                $hrdinfo->[$i]->{'lun'} = $6;
                $i++;                                              
	}
	else{
		next;
	}
	}
	close(VS);
	return @raidinfo_cache;
}
#Get Raid info ----------------for 3ware adapter only! #
sub get_raid_info_3w
{
    $cid = `/sbin/tw_cli/tw_cli show |grep c[0-9]`;
    $cid =~ /^(c\d+)\s+/;
    $cid = $1;

        my ($hrdinfo, @lsraid_info);
        $volroot = "/usrvol/";
        $hrdinfo = \@raidinfo_cache;
	$config{'amccpath'} = "/sbin/tw_cli/tw_cli";
        $cmd = $config{'amccpath'}.' /'.$cid.' show 2>/dev/null |';
        open(LSRAID, $cmd);
        while($line= <LSRAID>){
            if($line =~ /^(u\d*)\s+(\S+)\s+(\S+)\s+(\S*)\s+(\S*)\s+(\S+)/){

                $hrdinfo->[$i]->{'name'} = get_scsidev_3w($1);
                $ux = $1;
                $hrdinfo->[$i]->{'raidlevel'} =$2;
                $hrdinfo->[$i]->{'status'}= $3;
                $hrdinfo->[$i]->{'volname'} = get_3w_volname($ux);
                $i++;
            }else{
                next;
            }
        }
        close(LSRAID);
        return @raidinfo_cache;
}

#Get Raid info ----------------for HPT adapter only! #
sub get_raid_info_2220
{
    my ($raidinfo, @raid_info);
    $raidinfo = \@raid_info;
    $i=0;
    open(PV, "/proc/scsi/hptmv6/0");
    while($line = <PV>) {
      $line =~ s/\r|\n//g;
      $line =~ s/#.*$//g;
      if ($line =~ /DISK\s+(\d+)_(\d+)\S\s+.*(diskarray\d)\s+.*MB/) {
        $temparr = $3;
        $name = $2;
	@abc=("/dev/sda", "/dev/sdb", "/dev/sdc", "/dev/sdd", "/dev/sde", "/dev/sdf", "/dev/sdg", "/dev/sdh");
	$name=$abc[$name];
        if ($temparr =~ /diskarray/){
                $raidinfo->[$i]->{'name'} = $name;
                $raidinfo->[$i]->{'volname'} = $temparr;
                $i++;
        }
      }
      else {
         next;
      }
    }
    close(PV);
    return @raid_info;
}
sub get_raid_info
{
    my ($raidinfo, @raid_info);
    $raidinfo = \@raid_info;
    $i=0;
    open(PV, "/proc/scsi/hptmv/0");
    while($line = <PV>) {
      $line =~ s/\r|\n//g;
      $line =~ s/#.*$//g;
      if ($line =~ /(\d)\s+(\/dev\/sd\S)\s+.*\s+(\S+)\s+(\d+)MB/) {
        $temparr = $3;
        $name = $2;
        if ($temparr =~ /diskarray/){
                $raidinfo->[$i]->{'name'} = $name;
                $raidinfo->[$i]->{'volname'} = $temparr;
                $i++;
        }
      }
      else {
         next;
      }
    }
    close(PV);
    return @raid_info;

}
#Get VG info list;
sub get_vg_info
{
	my @vginfo;
	my @vginfob;
	my ($line, $vg, $pvnum, $lvnum, @pvs, @lvs, $status, $size, $free);
	open(VG, "lvm vgs --noheadings --units m 2>/dev/null |");
	my $i = 0;
	while($line = <VG>){
		$line =~ s/\r|\n//g;
		if($line =~ /\s+(\S+)\s+(\d+)\s+(\d+)\s+\S+\s+(\S+)\s+(\S+)M\s+(\S+)M/){
			$vg = $1;
			$pvnum = $2;
			$lvnum = $3;
			$status = $4;
			$size = $5;
			$free = $6;
			$i++;
		}else{
			next;
		}
		$vginfo[$i]->{'vg'} = $vg;
		$vginfo[$i]->{'pvnum'} = $pvnum;
		$vginfo[$i]->{'lvnum'} = $lvnum;
		if($status =~ /w/){
			$vginfo[$i]->{'status'} = $text{'lv_available'};
		}
		else{
			$vginfo[$i]->{'status'} = $text{'lv_unavailable'}
		}
		$vginfo[$i]->{'size'} = $size;
		$vginfo[$i]->{'free'} = $free;
	}
	close(VG);
	foreach $vgi (@vginfo) {
		if($vgi->{'vg'}) {
			push(@vginfob, $vgi);
		}
	} 
	return @vginfob;	
}
#Get all pvs of one VG 
sub get_pvs_of_vg
{
	my ($vg, @pvs) = @_;
	my $pv;
	my @vg_pvs;
	foreach $pv (@pvs) {
		if ($pv->{'vg'} eq $vg->{'vg'}) {
			push(@vg_pvs, $pv->{'pv'});
		}
	}
	return @vg_pvs;
}
#Get all LVs of one VG
sub get_lvs_of_vg
{
	my ($vg, @lvs) = @_;
	my $lv;
	my @vg_lvs;
	foreach $lv (@lvs) {
		if ($lv->{'vg'} eq $vg->{'vg'}) {
			push(@vg_lvs, $lv);
		}
	}	
	return @vg_lvs;
}
#Get snapshot lv info
sub get_snapshot_info
{
	my @snapshot;
	my @snapshotb;
	my ($line);
	my ($sv, $svname, $vg, $status, $originlv, $usage, $size, $svpath, $svdev);
	open(SN, "lvm lvs --noheadings --units m 2>/dev/null |");
	my $j = 0;
	while($line=<SN>){
		$line =~ s/\r|\n//g;
		if($line =~ /(\S+)\s+(vg\d)\s+(\S+)\s+(\S+)M\s+(volume\d+)\s+(\S+)/){
			$svname = $1;
			$sv = '/dev/'.$2.'/'.$svname;	
			$vg = $2;
			$status = $3;
			$size = $4;
			$originlv = $5;
			$usage = $6;
			$svpath = "/snapshot/".$svname;
			$svdev = "/dev/mapper/".$vg."-".$svname;
			
                        if($status =~ /\S+a\S$/) {
                                $status_a = $text{'lv_available'};
                        }
		}
		else{
			next;
		}
		$snapshot[$j]->{'sv'} = $sv;
		$snapshot[$j]->{'svname'} = $svname;
		$snapshot[$j]->{'vg'} =  $vg;
		$snapshot[$j]->{'size'} = $size;
		$snapshot[$j]->{'originlv'} = $originlv;
		$snapshot[$j]->{'usage'} = $usage;
		$snapshot[$j]->{'status_a'} = $status_a;
		$snapshot[$j]->{'svpath'} = $svpath;
		$snapshot[$j]->{'svdev'} = $svdev;
		@svstat = &vol_mount_status($svpath);
		$snapshot[$j]->{'status_m'} = $svstat[0];	
		$j++;
	}	
	close(SN);
	foreach $ss (@snapshot) {
		if ($ss->{'sv'}) {
			push (@snapshotb, $ss);
		}
	}	
	return @snapshotb;
}
#Get LV info list;
sub get_lv_info
{
	my @lvinfo;
	my @lvinfob;
	my ($line, $lv, $lvname, $vg, $status, $size, $openmark, $status_a, $status_o, $lvpath, @lvstat, @sizeinfo, $freesize, $snaps, $snapo);
	open(LV, "lvm lvs --noheadings --units m 2>/dev/null |");
	my $i=0;
	while($line=<LV>){
		$line =~ s/\r|\n//g;
		if($line =~ /\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)M/){
			$lvname = $1;
			$lv = '/dev/'.$2.'/'.$lvname;
			$vg = $2;
			$size = $4;
			$status = $3;
			if($status =~ /a/) {
				$status_a = $text{'lv_available'};
			}
			else{
				$status_a = $text{'lv_unavailable'};
			}
			if($status =~ /o$/){
				$status_o = 1;
			}
			else{
				$status_o = 0;
			}
			if($status =~ /^s/) {
				$snaps = 1;
			}
			else{
				$snaps = 0;
			}
			if($status =~ /^o/){
				$snapo = 1;
			}
			else{
				$snapo = 0;
			}
			$lvpath = "/usrvol/".$lvname;
			@lvstat = vol_mount_status($lvpath); 
			$i++;
		}else{
			next;
		}
		$lvinfo[$i]->{'lv'} = $lv;
		$lvinfo[$i]->{'lvname'} = $lvname; 
		$lvinfo[$i]->{'vg'} = $vg;
		$lvinfo[$i]->{'status'} = $status;
		$lvinfo[$i]->{'status_a'} = $status_a;
		$lvinfo[$i]->{'status_o'} = $status_o;
		$lvinfo[$i]->{'size'} = $size;
		$lvinfo[$i]->{'lvpath'} = $lvpath;
		$lvinfo[$i]->{'status_m'} = $lvstat[0];
		$lvinfo[$i]->{'status_i'} = check_istat($lv);
		$lvinfo[$i]->{'snapo'} = $snapo;
		$lvinfo[$i]->{'snaps'} = $snaps;
		if($lvstat[0]){
			@sizeinfo = got_vol_usage($lvpath);
			$freesize = int($sizeinfo[2] / 1024);
			$usedsize = int($sizeinfo[1] / 1024);
			$lvinfo[$i]->{'freesize'} = $freesize.'MB ';
			$lvinfo[$i]->{'usedsize'} = $usedsize;
			$lvinfo[$i]->{'usage'} = $sizeinfo[3];
		}
		
	}
	close(LV);
	foreach $lvi (@lvinfo) {
		if($lvi->{'lv'} && !($lvi->{'snaps'})) {
			push(@lvinfob, $lvi);
		}
	}
	rewrite_voltab(@lvinfob);
	return @lvinfob;	
}
#Get free PVs that can be created a new VG
sub get_free_pv
{
	my @pvinfo = @_;
	my @freepv;
	my $pv;
	foreach $pv (@pvinfo) {
		if (!$pv->{'vg'}) {
			push(@freepv, $pv);
		}
	}
	return @freepv;
}

# Get free vgname
sub get_free_vgname
{
	my @vginfo = @_;
	my $vg;
	my $vgnum = 8;
	my ($i, $j);
	my $found;
	my $tmpvg;
	my @freevgname;
	for($i=0; $i<$vgnum; $i++){
		$j = $i + 1;
		$found = 0;
		$tmpvg = "vg".$j;
		foreach $vg (@vginfo) {
			if($vg->{'vg'} eq $tmpvg) {
				$found = 1;
				last;
			}
		}	
		if(!$found){
			push(@freevgname, $tmpvg);
		}
	}
	return @freevgname;
}
#Get free volumes
sub get_free_volumes
{
	my @lvinfo = @_;
	my @usrvols = ('volume1', 'volume2', 'volume3', 'volume4', 'volume5', 'volume6', 'volume7', 'volume8', 'volume9', 'volume10', 'volume11', 'volume12', 'volume13', 'volume14', 'volume15','volume16');
	my @freevols = ();
	my ($vol, $lv, $found);
	foreach $vol (@usrvols) {
		$found = 0;
		foreach $lv (@lvinfo) {
			if($lv->{'lvname'} eq $vol) {
				$found = 1;
				last;
			}
		}	
		if (!$found) {
			push(@freevols, $vol);
		}
	}
	return @freevols;
}
#Create a PV 
sub create_pv
{

}
#Delete a PV
sub remove_pv
{

}
#Create VG
sub create_vg
{
	my ($vgname, @pvs) = @_;
	$pvstr = join(" ", @pvs);
	my $out = `/sbin/lvm vgcreate $vgname $pvstr`;
	return $?;
}
#Remove VG
sub remove_vg
{
	my $vg = $_[0];
	my $out = `/sbin/lvm vgremove $vg->{'vg'}`;
	return $?;
}
#Extend VG
sub extend_vg
{
	my $vg = $_[0];
	my $pv = $_[1];
	my $out = `/sbin/lvm vgextend $vg $pv`;
	return $?;
}
#Reduce VG
sub reduce_vg
{
	my $vg = $_[0];
	my $pv = $_[1];
	my $out = `/sbin/lvm vgreduce $vg $pv`;
	return $?;
}

sub merge_vg
{

}

sub split_vg
{

}

sub change_vg
{

}

sub create_lv
{
	my $lvname = $_[0];
	my $lvsize = $_[1];
	my $vgname = $_[2];
	my $out = `/sbin/lvm lvcreate -L $lvsize -n $lvname $vgname`;
	return $?;
}

sub remove_sv
{
        my $sv = $_[0];
        my $out = `/sbin/lvm lvremove $sv->{'sv'} -f`;
        return $?;
}

sub remove_lv
{
	my $lv = $_[0];
	my $out = `/sbin/lvm lvremove $lv->{'lv'} -f`;
	return $?;
}

sub extend_lv
{
	my ($lv, $size, $newsize);
	$lv = $_[0];
	$size = $_[1];
	$newsize = $_[2];
	my $out = ``;
	return $?;
}

sub reduce_lv
{

}

sub resize_lv
{
        my ($lv, $size, $newsize, $out);
        $lv = $_[0];
        $size = $_[1];
        $newsize = $_[2];
	my $newcap = $newsize."M";
	if($newsize > $size){
		$out = `/sbin/lvm lvextend -L $newcap $lv`;
		return $?;
	}
	elsif($newsize < $size){
		$out = `/sbin/lvm lvreduce -f -L $newcap $lv`;
		return $?;
	}
}

sub change_lv
{

}
# delete_voltab
sub delete_voltab
{

}
# rewrite_voltab(rf) for 3w system
sub rewrite_voltab
{
        my (@lvinfo, $lv, @newtab, $voltab);
	my ($lvdev, $lvpath, $volname, $status);
        @lvinfo = @_;
        push(@newtab, "volroot=/usrvol/\n");
	foreach $lv (@lvinfo) {
		$volname = $lv->{'lvname'};
		$lvdev = $lv->{'lv'};
		$lvpath = $lv->{'lvpath'};
		@mountstatus = vol_mount_status($lvpath);
		if($mountstatus[0]) {
			$status = 'normal';
			push(@newtab, join("\t", ($volname, $lvdev, $status, "\n")));
		}
	}

	$voltab = "/etc/nas/voltab";
        open(VOLTAB, "> $voltab");
        my $line;
        foreach $line (@newtab) {
                print VOLTAB $line;
        }
        close(VOLTAB);	
}

# get vol_mount_status(device)
# if the device is mounted, return the array (1, directory)
# else return (0, undef)
sub vol_mount_status
{
        my (@p, @mstatus);

        @mstatus = (0, undef);
        open(MTAB, "/etc/mtab");
        while(<MTAB>) {
                chop;
                s/#.*$//g;
                if (!/\S/) { next; }
                @p = split(/\s+/, $_);
                if ($p[1] eq $_[0]) {
                        #found
                        $mstatus[0] = 1;
                        $mstatus[1] = $p[1];
                        return @mstatus;
                }
        }
        close(MTAB);
        return @mstatus;
}

# got_vol_usage(directory)
# returns the amount of (total used avaiable use-percent) of the filesytem
# empty array if not appropriate
sub got_vol_usage
{
        `df -k $_[0]` =~ /Mounted on\n\S+\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/;
        return ($1, $2, $3, $4);
}
sub usagetext{
	my $usgtext = $text{'lv_used'}." ".$_[0].", ".$_[1]." ".$text{'lv_free'};
}

sub check_istat()
{
        my $dev = $_[0];
        open(FI, "/etc/ietd.conf");
        @iet=<FI>;
        close(FI);
        foreach $it (@iet) {
                $it =~ s/\r|\n//g;
                if($it =~ /(\/dev\/\S+),Type/){
                   if($dev eq $1){
                        return 1;
                   }
                }
        }
        return 0;
}
1;

